/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
define(["require", "exports", "../utils/convert"], function (require, exports, convert_1) {
    'use strict';
    Object.defineProperty(exports, "__esModule", { value: true });
    class ApplyRefactoringCommand {
        constructor(client, formattingOptionsManager, vscode) {
            this.client = client;
            this.formattingOptionsManager = formattingOptionsManager;
            this.vscode = vscode;
            this.id = ApplyRefactoringCommand.ID;
        }
        execute(document, file, refactor, action, range) {
            return __awaiter(this, void 0, void 0, function* () {
                yield this.formattingOptionsManager.ensureFormatOptionsForDocument(document, undefined);
                const args = Object.assign({}, convert_1.vsRangeToTsFileRange(file, range), { refactor,
                    action });
                const response = yield this.client.execute('getEditsForRefactor', args);
                if (!response || !response.body || !response.body.edits.length) {
                    return false;
                }
                const edit = this.toWorkspaceEdit(response.body.edits);
                if (!(yield this.vscode.workspace.applyEdit(edit))) {
                    return false;
                }
                const renameLocation = response.body.renameLocation;
                if (renameLocation) {
                    if (this.vscode.window.activeTextEditor && this.vscode.window.activeTextEditor.document.uri.fsPath === document.uri.fsPath) {
                        const pos = convert_1.tsLocationToVsPosition(renameLocation, this.vscode);
                        this.vscode.window.activeTextEditor.selection = new this.vscode.Selection(pos, pos);
                        yield this.vscode.commands.executeCommand('editor.action.rename');
                    }
                }
                return true;
            });
        }
        toWorkspaceEdit(edits) {
            const workspaceEdit = new this.vscode.WorkspaceEdit();
            for (const edit of edits) {
                for (const textChange of edit.textChanges) {
                    workspaceEdit.replace(this.client.asUrl(edit.fileName), convert_1.tsTextSpanToVsRange(textChange, this.vscode), textChange.newText);
                }
            }
            return workspaceEdit;
        }
    }
    ApplyRefactoringCommand.ID = '_typescript.applyRefactoring';
    class SelectRefactorCommand {
        constructor(doRefactoring, vscode) {
            this.doRefactoring = doRefactoring;
            this.vscode = vscode;
            this.id = SelectRefactorCommand.ID;
        }
        execute(document, file, info, range) {
            return __awaiter(this, void 0, void 0, function* () {
                const selected = yield this.vscode.window.showQuickPick(info.actions.map((action) => ({
                    label: action.name,
                    description: action.description
                })));
                if (!selected) {
                    return false;
                }
                return this.doRefactoring.execute(document, file, info.name, selected.label, range);
            });
        }
    }
    SelectRefactorCommand.ID = '_typescript.selectRefactoring';
    class TypeScriptRefactorProvider {
        constructor(client, formattingOptionsManager, commandManager, vscode) {
            this.client = client;
            this.vscode = vscode;
            if (!TypeScriptRefactorProvider.extractFunctionKind) {
                TypeScriptRefactorProvider.extractFunctionKind = this.vscode.CodeActionKind.RefactorExtract.append('function');
            }
            if (!TypeScriptRefactorProvider.extractFunctionKind) {
                TypeScriptRefactorProvider.extractConstantKind = this.vscode.CodeActionKind.RefactorExtract.append('constant');
            }
            const doRefactoringCommand = commandManager.register(new ApplyRefactoringCommand(this.client, formattingOptionsManager, this.vscode));
            commandManager.register(new SelectRefactorCommand(doRefactoringCommand, this.vscode));
        }
        provideCodeActions(document, _range, context, token) {
            return __awaiter(this, void 0, void 0, function* () {
                if (!this.client.apiVersion.has240Features()) {
                    return [];
                }
                if (context.only && !this.vscode.CodeActionKind.Refactor.contains(context.only)) {
                    return [];
                }
                if (!this.vscode.window.activeTextEditor) {
                    return [];
                }
                const editor = this.vscode.window.activeTextEditor;
                const file = this.client.normalizePath(document.uri);
                if (!file || editor.document.uri.fsPath !== document.uri.fsPath) {
                    return [];
                }
                if (editor.selection.isEmpty) {
                    return [];
                }
                const range = editor.selection;
                const args = convert_1.vsRangeToTsFileRange(file, range);
                try {
                    const response = yield this.client.execute('getApplicableRefactors', args, token);
                    if (!response || !response.body) {
                        return [];
                    }
                    const actions = [];
                    for (const info of response.body) {
                        if (info.inlineable === false) {
                            const codeAction = new this.vscode.CodeAction(info.description, this.vscode.CodeActionKind.Refactor);
                            codeAction.command = {
                                title: info.description,
                                command: SelectRefactorCommand.ID,
                                arguments: [document, file, info, range]
                            };
                            actions.push(codeAction);
                        }
                        else {
                            for (const action of info.actions) {
                                const codeAction = new this.vscode.CodeAction(action.description, TypeScriptRefactorProvider.getKind(action, this.vscode));
                                codeAction.command = {
                                    title: action.description,
                                    command: ApplyRefactoringCommand.ID,
                                    arguments: [document, file, info.name, action.name, range]
                                };
                                actions.push(codeAction);
                            }
                        }
                    }
                    return actions;
                }
                catch (_a) {
                    return [];
                }
            });
        }
        static getKind(refactor, vscode) {
            if (refactor.name.startsWith('function_')) {
                return TypeScriptRefactorProvider.extractFunctionKind;
            }
            else if (refactor.name.startsWith('constant_')) {
                return TypeScriptRefactorProvider.extractConstantKind;
            }
            return vscode.CodeActionKind.Refactor;
        }
    }
    exports.default = TypeScriptRefactorProvider;
});
